package academic.ui.client.presenter;

import java.util.ArrayList;

import academic.ui.client.AppServiceAsync;
import academic.ui.client.event.LogOutEvent;
import academic.ui.client.event.NameChangeEvent;
import academic.ui.client.event.NameChangedEventHandler;
import academic.ui.client.event.UploadPhotoEvent;
import academic.ui.client.event.UploadPhotoEventHandler;
import academic.ui.client.place.Tokens;
import academic.ui.client.jquery.Facebook;
import academic.ui.client.widgets.PickCityGraph;
import academic.ui.client.widgets.SlideDealsGraph;
import academic.ui.client.widgets.TodayDealsGraph;
import academic.ui.client.widgets.forms.PickCityForm;
import academic.ui.client.widgets.tools.Scrollable;
import academic.ui.client.widgets.tools.ToolTip;
import ecommerce.soco.shared.*;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ListBox;
import com.google.inject.Inject;
import com.gwtplatform.mvp.client.EventBus;
import com.gwtplatform.mvp.client.Presenter;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.ContentSlot;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.PlaceRequest;
import com.gwtplatform.mvp.client.proxy.Proxy;
import com.gwtplatform.mvp.client.proxy.RevealContentHandler;
import com.gwtplatform.mvp.client.proxy.RevealRootContentEvent;

public class AppPresenter extends 
Presenter<AppPresenter.MyView,AppPresenter.MyProxy>{
	
	@ContentSlot
	public static final Type<RevealContentHandler<?>> slot = new Type<RevealContentHandler<?>>();
		  		
	public static final String SELECTOR = "headerSignInLink";
	
	private AppServiceAsync service;
	
	private PlaceManager placeManager;
	private AppPresenter myAppPresenter;
	@Inject
	public AppPresenter(EventBus eventBus, MyView view, MyProxy proxy, AppServiceAsync service,PlaceManager placeManager) {
		super(eventBus, view, proxy);
		this.service=service;
		this.placeManager=placeManager;
		myAppPresenter = this;
	}

	@ProxyStandard
	public interface MyProxy extends Proxy<AppPresenter>  {}

	public interface MyView extends View {

		boolean sidePanelOff();

		HasClickHandlers signInLink();

		HasClickHandlers signOutLink();

		HasClickHandlers home();

		HasClickHandlers myAccount();

		void reset();

		void setLoginInfo(GWT_Customer customer);

		void notLoggedIn();

		HasClickHandlers myDealsLink();

		HasClickHandlers myGiftsLink();

		HasClickHandlers myAccountsLink();

		HasClickHandlers myProfileLink();

		HasClickHandlers deals();

		HasClickHandlers recentDeals();

		void updateAppContentHeight();

		void changeName(String newName);

		void updateImage(String url);

		void facebookLogin();

		void notLoggedInFB();

		void updateRecentDealsTooltip(ArrayList<GWT_Product> products);

		SlideDealsGraph getSlideDeals();

		TodayDealsGraph getTodayDealsGraph();

		void updateTodayDealsTooltip(ArrayList<GWT_Product> products);

		HasClickHandlers getChooseCityLink();

		PickCityGraph getCityGraph();
	}
	

	@Override
	protected void revealInParent() {
		RevealRootContentEvent.fire( this, this );
		Log.debug("AppPresenter revealInParent");
	}
	
	@Override
	public void onReveal()  {
		super.onReveal();
		Log.debug("AppPresenter onReveal");
		service.setCity(new AsyncCallback<Boolean>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(Boolean result) {
				// TODO Auto-generated method stub
				
			}
			
		});
	   ToolTip.initLongTooltip();
	}
	
	@Override
	public void onBind() {
		super.onBind();
		
		service.getParticipatingCities(new AsyncCallback<ArrayList<GWT_City>>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(ArrayList<GWT_City> cities) {
				if(cities!=null)
					getView().getCityGraph().setListBoxValues(cities);
			}
			
		});
		
		registerHandler(Window.addResizeHandler(new ResizeHandler() {

			@Override
			public void onResize(ResizeEvent event) {
				getView().updateAppContentHeight();
			}
			
		}));
		
		
		registerHandler(getView().signInLink().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.login).with("selector", AppPresenter.SELECTOR));
			}
			
		}));
		
		registerHandler(getView().signOutLink().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				service.logout(new AsyncCallback<Boolean>() {

					@Override
					public void onFailure(Throwable caught) {
						// TODO Auto-generated method stub
						
					}

					@Override
					public void onSuccess(Boolean result) {
						if(result)
						{
							getView().notLoggedIn();
							getView().notLoggedInFB();
							LogOutEvent.fire(getEventBus());
							placeManager.revealPlace(new PlaceRequest(Tokens.primary));
						}
						else
							Log.debug("There is a problem with the server");
					}
					
				});
			}
			
		}));
		
		registerHandler(getView().home().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.primary));
			}
			
		}));
		
		registerHandler(getView().deals().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.deals));
			}
			
		}));
		
		registerHandler(getView().myAccount().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.myAccount).with("tab", AccountPresenter.MYACCOUNTTAB));
			}
			
		}));
		registerHandler(getView().myAccountsLink().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.myAccount).with("tab", AccountPresenter.MYACCOUNTTAB));
			}
			
		}));
		registerHandler(getView().myDealsLink().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.myAccount).with("tab", AccountPresenter.MYDEALSTAB));
			}
			
		}));
		registerHandler(getView().myGiftsLink().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.myAccount).with("tab", AccountPresenter.MYGROUPSTAB));
			}
			
		}));
		
		registerHandler(getView().recentDeals().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				placeManager.revealPlace(new PlaceRequest(Tokens.recentDeals));
			}
			
		}));
		
		registerHandler(getView().getCityGraph().addChangeHandler(new ChangeHandler() {

			@Override
			public void onChange(ChangeEvent event) {
				Log.debug("onChange City Graph");
				service.updateCity(((ListBox)event.getSource()).getValue(((ListBox)event.getSource()).getSelectedIndex()), new AsyncCallback<Boolean>(){

					@Override
					public void onFailure(Throwable caught) {
						// TODO Auto-generated method stub
						
					}

					@Override
					public void onSuccess(Boolean result) {
						if(result)
							placeManager.revealPlace(new PlaceRequest(Tokens.primary));
					}
					
				});
			}
			
		}));
		
		registerHandler(getEventBus().addHandler(NameChangeEvent.getType(),new NameChangedEventHandler() {

			@Override
			public void onNameChangeEvent(NameChangeEvent event) {
				getView().changeName(event.getNewName());
			}
			
		}));
		
		registerHandler(getEventBus().addHandler(UploadPhotoEvent.getType(), new UploadPhotoEventHandler() {

			@Override
			public void onUploadPhotoEvent(UploadPhotoEvent event) {
				getView().updateImage(event.getFilename());
			}
			
		}));
		
		DeferredCommand.addCommand(new Command() {

			@Override
			public void execute() {
				Log.debug("AppPresenter onBind DefferedCommand");
				Facebook.init();
				initFacebook(myAppPresenter);
			}
			
		});
		Log.debug("AppPresenter onBind");
	}
	
	@Override
	public void onReset() {
		super.onReset();
		Log.debug("AppPresenter onReset");
		//getView().updateAppContentHeight();
		
		service.getRecentProducts(new AsyncCallback<ArrayList<GWT_Product>>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(ArrayList<GWT_Product> result) {
				getView().updateRecentDealsTooltip(result);
				DeferredCommand.addCommand(new Command() {

					@Override
					public void execute() {
						Scrollable.scrollDeals();
					}
					
				});
				for(HasClickHandlers handle : getView().getSlideDeals().productImageClickables())
				{
					registerHandler(handle.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							placeManager.revealPlace(new PlaceRequest(Tokens.productFull).with("id", event.getRelativeElement().getId()).with("expired", "true"));
						}
						
					}));
				}
				
			}
			
		});
		service.getActiveProducts(new AsyncCallback<ArrayList<GWT_Product>>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(ArrayList<GWT_Product> products) {
				getView().updateTodayDealsTooltip(products);
				
				for(HasClickHandlers handle : getView().getTodayDealsGraph().productImageClickables())
				{
					registerHandler(handle.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							placeManager.revealPlace(new PlaceRequest(Tokens.productFull).with("id", event.getRelativeElement().getId()));
						}
						
					}));
				}
			}
			
		});
		service.getUser(new AsyncCallback<GWT_Customer>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(GWT_Customer user) {
				if(user!=null)
				{
					getView().setLoginInfo(user);
				}
				else
				{
					getView().notLoggedIn();
					//reset the app if missing basic session parameters
					service.appReset(new AsyncCallback<Boolean>() {

						@Override
						public void onFailure(Throwable caught) {
							// TODO Auto-generated method stub
							
						}

						@Override
						public void onSuccess(Boolean result) {
							if(result)
							{Log.debug("reset the app");
								placeManager.revealPlace(new PlaceRequest(Tokens.primary));
							}
						}
						
					});
				}
			
				
			}
		});
	}
	
	public native void initFacebook(AppPresenter myApp) /*-{
		
			//handles the case that the user is already logged in
		    $wnd.FB.getLoginStatus(function(response) {
			  	if (response.session) {
			  		$wnd.FB.api('/me', function(response) {
            		var query = $wnd.FB.Data.query('select email from user where uid={0}', response.id);
            		query.wait(function(rows) {
            			myApp.@academic.ui.client.presenter.AppPresenter::loginUser(Ljava/lang/String;)(rows[0].email);
            		});
			  		});
			  		
			    	myApp.@academic.ui.client.presenter.AppPresenter::facebookLogin()();
			  	} else {
			    	//handles the login event
					$wnd.FB.Event.subscribe('auth.login',function(response) {
					$wnd.FB.api('/me', function(response) {
	            		var query = $wnd.FB.Data.query('select email from user where uid={0}', response.id);
	            		query.wait(function(rows) {
	            			myApp.@academic.ui.client.presenter.AppPresenter::loginUser(Ljava/lang/String;)(rows[0].email);
	            		});
				  		});
			            myApp.@academic.ui.client.presenter.AppPresenter::facebookLogin()();
					});
			  	}
			});
				
			
			
			
		}-*/;
	
	public  void facebookLogin() {
		getView().facebookLogin();
	}
	
	/**
	 * Determine if this facebook email corresponds with an email in our system
	 * if so check with the user first and force them to enter the password we've associated with their account,
	 * if not simply add the email to our email list and prompt the user to register
	 * @param email
	 */
	public void loginUser(final String email) {
		service.loginFBUser(email,new AsyncCallback<Boolean>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(Boolean result) {
				placeManager.revealPlace(new PlaceRequest(Tokens.login).with("email",email).with("selector", AppPresenter.SELECTOR));
			}
			
		});
	}
	
	
}
